from datetime import timedelta
from typing import Dict, Optional
from sqlalchemy.orm import Session

from app.models.user import User
from app.services.user_service import UserService
from app.exception import AuthenticationError, ValidationError
from app.utils.jwt_util import create_access_token
from app.utils.redis_util import RedisUtil
from app.utils.config_loader import config

class AuthService:
    """认证服务类"""
    
    @staticmethod
    def register(db: Session, username: str, email: str, password: str) -> User:
        """用户注册
        
        Args:
            db: 数据库会话
            username: 用户名
            email: 邮箱
            password: 密码
            
        Returns:
            User: 创建的用户对象
            
        Raises:
            ValidationError: 用户名或邮箱已存在
        """
        # 使用UserService创建用户
        return UserService.create_user(db, username, email, password)
    
    @staticmethod
    def login(
        db: Session, 
        username: str, 
        password: str,
        expires_delta: Optional[timedelta] = None
    ) -> Dict:
        """用户登录
        
        Args:
            db: 数据库会话
            username: 用户名
            password: 密码
            expires_delta: 令牌过期时间
            
        Returns:
            Dict: 包含访问令牌和用户信息的字典
            
        Raises:
            AuthenticationError: 用户名或密码错误
            AuthenticationError: 用户未激活
        """
        # 查找用户
        user = db.query(User).filter(User.username == username).first()
        
        # 验证用户存在且密码正确
        if not user or not UserService.verify_password(password, user.password):
            raise AuthenticationError("用户名或密码错误")
        
        # 检查用户是否激活
        if not user.is_active:
            raise AuthenticationError("用户未激活，请联系管理员")
        
        # 生成访问令牌
        token_data = {"sub": user.username, "user_id": user.id}
        access_token = create_access_token(
            data=token_data,
            expires_delta=expires_delta
        )
        
        # 计算过期时间（秒）
        if expires_delta:
            expires_in = int(expires_delta.total_seconds())
        else:
            expires_in = config.security.access_token_expire_minutes * 60
            
        # 将令牌存入Redis，用于后续验证或注销
        RedisUtil.set(
            f"token:{user.id}",
            access_token,
            expire=expires_in
        )
        
        # 返回令牌和用户信息
        return {
            "access_token": access_token,
            "token_type": "bearer",
            "user": user
        }
    
    @staticmethod
    def logout(user_id: int) -> bool:
        """用户登出
        
        Args:
            user_id: 用户ID
            
        Returns:
            bool: 是否成功登出
        """
        # 从Redis中删除令牌
        RedisUtil.delete(f"token:{user_id}")
        return True
